/*
 * FairyResource.cpp
 *
 *  Created on: 2013. 9. 12.
 *      Author: mega@gamevil.com
 */

#include "../User.h"
#include "../Enum.h"
#include "../engine.h"
#include "../NUtil/Utils.h"
#include "../NLogic/Bag.h"
#include "../NLogic/Item.h"
#include "../NResource/Static.h"

#include "FairyGachyaResource.h"

namespace ProjectZ { namespace NResource {

FairyGachyaResource::FairyGachyaResource()
{
	pFairyAD	= new FairyGachyaData;
	pFairyIOS	= new FairyGachyaData;
}

FairyGachyaResource::~FairyGachyaResource()
{
	delete pFairyAD;
	delete pFairyIOS;
}

bool FairyGachyaResource::LoadResource()
{
	if (false == pFairyAD->LoadResource(MARKET_GOOGLE, SC_KAKAO_GOOGLE))
		return false;

	if (false == pFairyIOS->LoadResource(MARKET_IOS, SC_KAKAO_IOS))
		return false;

	return true;
}

FairyGachyaData::Flyweight * FairyGachyaResource::GetFly(int company, int saleCode, FairyGachyaData::Key & clsKey)
{
	NUtil::MarketType marketType = NUtil::GetMarketType(company, saleCode);

	switch (marketType)
	{
	case NUtil::MarketType::AD_KAKAO:
		return pFairyAD->GetFly(clsKey);

	case NUtil::MarketType::IOS_KAKAO:
		return pFairyIOS->GetFly(clsKey);

	default:
		return NULL;
	}

	return NULL;
}

FairyGachyaData * FairyGachyaResource::GetDataPtr(int company, int saleCode)
{
	NUtil::MarketType marketType = NUtil::GetMarketType(company, saleCode);

	switch (marketType)
	{
	case NUtil::MarketType::AD_KAKAO:
		return pFairyAD;

	case NUtil::MarketType::IOS_KAKAO:
		return pFairyIOS;

	default:
		return NULL;
	}

	return NULL;
}

FairyGachyaData::~FairyGachyaData()
{
	std::for_each(clsFlyTree.begin(), clsFlyTree.end(), ProjectZ::NUtil::del_second_ptr<FAIRYTREE::value_type>);
}

void FairyGachyaData::Clear()
{
	std::for_each(clsFlyTree.begin(), clsFlyTree.end(), ProjectZ::NUtil::del_second_ptr<FAIRYTREE::value_type>);
	clsFlyTree.clear();
}

bool FairyGachyaData::LoadResource(int company, int saleCode)
{
	::Database::Command::Auto clsAuto(::Database::GETCOMMANDPOOL());
	clsAuto->SetQueryType(::Database::Command::SELECT);
	clsAuto->MakeQuery("SELECT NATIONAL_CODE, type, sub_type, value1, value2, value3 FROM resource_fairygachya WHERE company=%d AND sale_cd=%d ORDER BY type, sub_type", company, saleCode);

	if (false == ::Database::GETSESSION()->SyncExecute(1, clsAuto))
		return false;

	if( clsAuto->GetErrorIdx() != 0 )
		return false;

	if (0 == clsAuto->ResultRowCount())
		return false;

	Clear();

	while( clsAuto->Next() )
	{
		::Toolkit::Str<3> NATIONAL_CODE;
		FairyGachyaData::Flyweight * pFly = new FairyGachyaData::Flyweight;

		clsAuto->GetRecord() >> NATIONAL_CODE >> pFly->_TYPE >> pFly->_SUB_TYPE >> pFly->_VALUE1 >> pFly->_VALUE2 >> pFly->_VALUE3;

		if (0 != Config::Instance().GetResourceDatabase()._strNational.compare(NATIONAL_CODE.c_str()))
		{
			DEBUGLOG("%s:%d NATIONAL_CODE ERROR!!! Config National Code [%s] , Resource National Code [%s]",
					__FILE__, __LINE__,
					Config::Instance().GetResourceDatabase()._strNational.c_str(),
					NATIONAL_CODE.c_str());
			return false;
		}

		clsFlyTree[FairyGachyaData::Key(pFly->_TYPE, pFly->_SUB_TYPE)] = pFly;
	}

//	PrintFlyTree(company, saleCode);

	return true;
}

void
FairyGachyaData::PrintFlyTree(int company, int salecode)
{
	DEBUGLOG("company=%d, salecode=%d", company, salecode);
	std::for_each(clsFlyTree.begin(), clsFlyTree.end(), [&](FAIRYTREE::value_type & v) {
		DEBUGLOG("%d, %d, %d, %d, %d", v.first.type, v.first.sub_type, v.second->_VALUE1, v.second->_VALUE2, v.second->_VALUE3);
	});
	DEBUGLOG("-------------------------------------------------------");

}


FairyGachyaData::Flyweight * FairyGachyaData::GetFly(FairyGachyaData::Key & clsKey)
{
	auto iter = clsFlyTree.find(clsKey);

	if (iter == clsFlyTree.end())
		return NULL;

	return iter->second;
}

void
FairyGachyaResource::FairyGachyaForTEST(User * pUser, int level)
{
	FairyGachyaData * pFairy = this->GetDataPtr(pUser->GetUserInfo().company, pUser->GetUserInfo().sale_code);

	if (pFairy == NULL)
		return;

	NResource::BalanceData * pBalance = NResource::Static::InstancePtr()->GetBalance()->GetBalancePtr(pUser);

	if (NULL == pBalance)
		return;

	NLogic::Bag * pBag = pUser->GetBag(static_cast<INVEN_BAG_TYPE>(BAG_TYPE_FAIRY));
	if (NULL == pBag)
		return;

	NLogic::Item::Data clsData;

	// 페어리 레벨 결정
	clsData.level	= level;

	// 페어리 등급 결정
	clsData.quality	= GetFairyQuality(pFairy, false, 0);

	// 페어리 속성 결정
	clsData.eff_type[0]	= GetFairyAttrType(pFairy, false, -1);

	// 페어리 전투 타입 결정
	clsData.eff_pos[0]	= GetFairyBattleType(pFairy, false);

	// 페어리 패시브 갯수
	int passive	= GetFairyPassiveCount(pFairy, false, clsData.quality);

	// 페어리 버프
	int buff	= GetFairyBuff(pFairy, pBalance, false, clsData.quality);

	// 페어리 타입
	int fairytype = GetFairyType(pFairy, false);

	// 페어리 정보 설정
	SetFairyInfo(pFairy, pBalance, clsData, passive, buff, fairytype, false);

	bool bBagFull = false;
	pBag->AddItemWithData(clsData, bBagFull);
}

void FairyGachyaResource::SetBaseFairyInfo(User * pUser, NLogic::Item::Data & clsData, int classType)
{
	FairyGachyaData * pFairy = this->GetDataPtr(pUser->GetUserInfo().company, pUser->GetUserInfo().sale_code);

	if (pFairy == NULL)
		return;

	NResource::BalanceData * pBalance = NResource::Static::InstancePtr()->GetBalance()->GetBalancePtr(pUser);

	if (NULL == pBalance)
	{
		DEBUGLOG("%s : pBalance is NULL!", __FUNCTION__);
		return;
	}

	// 최초 캐릭터 생성시 지급되는 페어리의 타입은 기본 타입
	int fairyType = 0;

	// 최초 캐릭터 생성시 지급되는 페어리는 냉기
	clsData.eff_type[0] = 1;

	clsData.tid			= (fairyType * 4) + clsData.eff_type[0];
	clsData.level		= 1;
	clsData.quality		= 0;
	clsData.quantity	= 1;
	clsData.class_type	= -1;
	clsData.bag_type	= INVEN_BAG_TYPE::BAG_TYPE_FAIRY;
	clsData.sub_type	= EnumClassItemTableType::CLASS_ITEM_TABLE_FAIRY;
	clsData.eff_pos[0]	= 2;	// 페어리 전투 타입 (기본형)

	// 페어리 패시브 스킬1
	clsData.eff_value[0]	= NUtil::GetRandBetween(pBalance->GetValue(EM_FAIRY_PASSIVE_TID_MIN), pBalance->GetValue(EM_FAIRY_PASSIVE_TID_MAX));

	// 페어리 패시브 스킬1 레벨
	clsData.eff_pos[1]	= 1;

	// 페어리 속성 공격값
	clsData.eff_value[1]	= 7;

    switch (clsData.eff_type[0])
    {
    case 0:	// 화염
    	clsData.eff_value[2] = 7;
    	clsData.eff_value[3] = 1;
    	clsData.eff_value[4] = 1;
    	clsData.eff_value[5] = 1;
        break;

    case 1:	// 냉기
    	clsData.eff_value[2] = 1;
        clsData.eff_value[3] = 7;
        clsData.eff_value[4] = 1;
        clsData.eff_value[5] = 1;
        break;

    case 2:	// 신성
    	clsData.eff_value[2] = 1;
    	clsData.eff_value[3] = 1;
    	clsData.eff_value[4] = 7;
    	clsData.eff_value[5] = 1;
        break;

    case 3:	// 암흑
    	clsData.eff_value[2] = 1;
    	clsData.eff_value[3] = 1;
    	clsData.eff_value[4] = 1;
    	clsData.eff_value[5] = 7;
        break;
    }

	clsData.evolve_point	= -1;
	clsData.evolve_percent	= -1;
}


bool
FairyGachyaResource::IsFairyGachyaEvent(User * pUser)
{
	return Static::InstancePtr()->GetEventTime()->IsFairyGachyaEvent(pUser);
}

int
FairyGachyaResource::GetFairyLevel(FairyGachyaData * pFairy, bool bEvent)
{
	/*
	 * 페어리의 레벨을 결정한다
	 */
	int type = static_cast<int>(EM_FAIRY_GACHYA_LEVEL_RATE);

	if (true == bEvent) {
		type = static_cast<int>(EM_FAIRY_GACHYA_LEVEL_RATE_EVENT);
	}

	int accRate = 0;
	int randRate = rand() % 1000;

	FairyGachyaData::FAIRYTREE::const_iterator citer = pFairy->GetTree().begin();

	for ( ; citer != pFairy->GetTree().end(); citer++)
	{
		if (citer->second->_TYPE != type)
			continue;

		accRate += citer->second->_VALUE1;

		if (randRate < accRate)
		{
			break;
		}
	}

	int level = NUtil::GetRandBetween(citer->second->_SUB_TYPE - 9, citer->second->_SUB_TYPE);

	return level;
}

int
FairyGachyaResource::GetFairyQuality(FairyGachyaData * pFairy, bool bEvent, int gachyaQuality)
{
	/*
	 * 페어리의 등급을 결정한다
	 */
	int type = static_cast<int>(EM_FAIRY_GACHYA_QUALITY_RATE);

	if (true == bEvent) {
		type = static_cast<int>(EM_FAIRY_GACHYA_QUALITY_RATE_EVENT);
	}

	int accRate = 0;
	int randRate = rand() % 1000;

	FairyGachyaData::FAIRYTREE::const_iterator citer = pFairy->GetTree().begin();

	for ( ; citer != pFairy->GetTree().end(); citer++)
	{
		if (citer->second->_TYPE != type)
			continue;

		switch (gachyaQuality)
		{
		case 0: accRate += citer->second->_VALUE1; break;	// 최소 1성 이상
		case 1: accRate += citer->second->_VALUE2; break;	// 최소 2성 이상
		case 2: accRate += citer->second->_VALUE3; break;	// 최소 3성 이상
		}

		if (randRate < accRate)
			break;
	}

	int quality = 0;

	if (NULL != citer->second)
		quality = citer->second->_SUB_TYPE;

	return quality;
}

int
FairyGachyaResource::GetFairyAttrType(FairyGachyaData * pFairy, bool bEvent, int excludeType)
{
	/*
	 * 페어리의 속성타입을 결정한다
	 *
	 * 연속 2회 뽑힌 속성 확률 = A
	 * 뽑히지 않은 나머지 속성 확률 = B
	 * 변동될 나머지 속성 확률 = B1
	 * B1 = B * (100/(100-A))
	 */

	int type = static_cast<int>(EM_FAIRY_GACHYA_ATTR_RATE);

	if (true == bEvent) {
		type = static_cast<int>(EM_FAIRY_GACHYA_ATTR_RATE_EVENT);
	}

	int excludeTypeRate = 0;

	// 뽑기 속성 중복 제거
	if (-1 < excludeType)
	{
		FairyGachyaData::Key clsKey(type, excludeType);
		FairyGachyaData::Flyweight * pFly = pFairy->GetFly(clsKey);

		if (NULL != pFly)
			excludeTypeRate = pFly->_VALUE1;
	}

	int accRate = 0;
	int randRate = rand() % 100;

	FairyGachyaData::FAIRYTREE::const_iterator citer = pFairy->GetTree().begin();

	for ( ; citer != pFairy->GetTree().end(); citer++)
	{
		if (citer->second->_TYPE != type)
			continue;

		if (citer->second->_SUB_TYPE == excludeType)
			continue;

		int rate = ceil(citer->second->_VALUE1 * (100 / (double)(100 - excludeTypeRate)));

		accRate += rate;

		if (randRate < accRate)
			break;
	}

	int attrType = citer->second->_SUB_TYPE;

	return attrType;
}

int
FairyGachyaResource::GetFairyBattleType(FairyGachyaData * pFairy, bool bEvent)
{
	/*
	 * 페어리의 전투타입을 결정한다
	 */
	int type = static_cast<int>(EM_FAIRY_GACHYA_BATTLETYPE_RATE);

	if (true == bEvent) {
		type = static_cast<int>(EM_FAIRY_GACHYA_BATTLETYPE_RATE_EVENT);
	}

	int accRate = 0;
	int randRate = rand() % 100;

	FairyGachyaData::FAIRYTREE::const_iterator citer = pFairy->GetTree().begin();

	for ( ; citer != pFairy->GetTree().end(); citer++)
	{
		if (citer->second->_TYPE != type)
			continue;

		accRate += citer->second->_VALUE1;

		if (randRate < accRate)
			break;
	}

	int battleType = citer->second->_SUB_TYPE;

	return battleType;
}

int
FairyGachyaResource::GetFairyPassiveCount(FairyGachyaData * pFairy, bool bEvent, int quality)
{
	/*
	 * 페어리가 보유할 패시브 스킬의 갯수를 결정한다
	 */

	int type = static_cast<int>(EM_FAIRY_GACHYA_PASSIVE_RATE);

	if (true == bEvent) {
		type = static_cast<int>(EM_FAIRY_GACHYA_PASSIVE_RATE_EVENT);
	}

	int accRate = 0;
	int passiveCount = 0;
	int randRate = rand() % 100;

	FairyGachyaData::Key clsKey(type, quality);
	FairyGachyaData::Flyweight * pFly = pFairy->GetFly(clsKey);

	if (NULL == pFly)
	{
		DEBUGLOG("GetFairyPassiveCount : pFly is NULL!! type=%d, quality=%d", type, quality);
		return 1;
	}

	for ( ; passiveCount < 3; passiveCount++)
	{
		switch (passiveCount)
		{
		case 0 : accRate += pFly->_VALUE1; break;
		case 1 : accRate += pFly->_VALUE2; break;
		case 2 : accRate += pFly->_VALUE3; break;
		}

		if (randRate < accRate)
		{
			passiveCount++;
			break;
		}
	}

	return passiveCount;
}

int
FairyGachyaResource::GetFairyBuff(FairyGachyaData * pFairy, NResource::BalanceData * pBalance, bool bEvent, int quality)
{
	/*
	 * 페어리 버프 보유 여부를 결정한다.
	 */
	int type = static_cast<int>(EM_FAIRY_GACHYA_BUFF_RATE);

	if (true == bEvent) {
		type = static_cast<int>(EM_FAIRY_GACHYA_BUFF_RATE_EVENT);
	}

	FairyGachyaData::Key clsKey(type, quality);
	FairyGachyaData::Flyweight * pFly = pFairy->GetFly(clsKey);

	if (NULL == pFly)
	{
		DEBUGLOG("GetFairyBuff : pFly is NULL!! type=%d, quality=%d", type, quality);
		return -1;
	}

	int accRate = pFly->_VALUE1;
	int randRate = rand() % 100;

	if (randRate < accRate)
		return NUtil::GetRandBetween(pBalance->GetValue(EM_FAIRY_BUFF_TID_MIN), pBalance->GetValue(EM_FAIRY_BUFF_TID_MAX));

	return -1;
}

int
FairyGachyaResource::GetFairyType(FairyGachyaData * pFairy, bool bEvent)
{
	/*
	 * 페어리의 전투타입을 결정한다
	 */
	int type = static_cast<int>(EM_FAIRY_GACHYA_TYPE_RATE);

	if (true == bEvent) {
		type = static_cast<int>(EM_FAIRY_GACHYA_TYPE_RATE_EVENT);
	}

	int accRate = 0;
	int randRate = rand() % 100;

	FairyGachyaData::FAIRYTREE::const_iterator citer = pFairy->GetTree().begin();

	for ( ; citer != pFairy->GetTree().end(); citer++)
	{
		if (citer->second->_TYPE != type)
			continue;

		accRate += citer->second->_VALUE1;

		if (randRate < accRate)
			break;
	}

	int fairyType = citer->second->_SUB_TYPE;

	return fairyType;
}

bool
FairyGachyaResource::FairyGachya(User * pUser, NLogic::Item::Data & clsData, int excludeType, int gachyaQuality)
{

	FairyGachyaData * pFairy = this->GetDataPtr(pUser->GetUserInfo().company, pUser->GetUserInfo().sale_code);

	if (pFairy == NULL)
	{
		DEBUGLOG("%s : pFairy is NULL!", __FUNCTION__);
		return false;
	}

	NResource::BalanceData * pBalance = NResource::Static::InstancePtr()->GetBalance()->GetBalancePtr(pUser);

	if (NULL == pBalance)
	{
		DEBUGLOG("%s : pBalance is NULL!", __FUNCTION__);
		return false;
	}

	bool bEvent = IsFairyGachyaEvent(pUser);

	// 페어리 레벨 결정
	clsData.level	= GetFairyLevel(pFairy, bEvent);

	// 페어리 등급 결정
	clsData.quality	= GetFairyQuality(pFairy, bEvent, gachyaQuality);

	if (true == Static::Instance().GetContentsOpenResource()->IsOpen(CHINA_CONTENTS))
	{
		int maxLevel = (clsData.quality + 1) * 10;

		if (clsData.level > maxLevel)
		{
			clsData.level = maxLevel;
		}
	}

	// 페어리 속성 결정
	clsData.eff_type[0]	= GetFairyAttrType(pFairy, bEvent, excludeType);

	// 페어리 전투 타입 결정
	clsData.eff_pos[0]	= GetFairyBattleType(pFairy, bEvent);

	// 페어리 패시브 갯수
	int passive	= GetFairyPassiveCount(pFairy, bEvent, clsData.quality);

	// 페어리 버프
	int buff	= GetFairyBuff(pFairy, pBalance, bEvent, clsData.quality);

	// 페어리 타입
	int fairytype = GetFairyType(pFairy, bEvent);

	// 페어리 정보 설정
	if (false == SetFairyInfo(pFairy, pBalance, clsData, passive, buff, fairytype, bEvent))
	{
		return false;
	}

	return true;
}


bool
FairyGachyaResource::FairyRebirth(User * pUser, NLogic::Item::Data & clsData, std::vector<NLogic::Item *> & fairys)
{
	FairyGachyaData * pFairy = this->GetDataPtr(pUser->GetUserInfo().company, pUser->GetUserInfo().sale_code);

	if (pFairy == NULL)
	{
		DEBUGLOG("%s : pFairy is NULL!", __FUNCTION__);
		return false;
	}

	NResource::BalanceData * pBalance = NResource::Static::InstancePtr()->GetBalance()->GetBalancePtr(pUser);

	if (NULL == pBalance)
	{
		DEBUGLOG("%s : pBalance is NULL!", __FUNCTION__);
		return false;
	}

	int fairyCount = static_cast<int>(fairys.size());

	// 페어리 환생 레벨 결정
	int maxQuality = 0;
	int accPoint = 0;
	int accLevel = 0;
	for (int i = 0; i < fairyCount; i++)
	{
		if (fairys[i]->GetData().quality > maxQuality)
		{
			maxQuality = fairys[i]->GetData().quality;
		}

		int point = (fairys[i]->GetData().quality * pBalance->GetValue(EM_FAIRY_REBIRTH_LEVEL_POINT_GAP)) + pBalance->GetValue(EM_FAIRY_REBIRTH_LEVEL_POINT_START);
		accPoint = accPoint + (static_cast<int>(point * fairys[i]->GetData().level) / 100);
		accLevel = accLevel + fairys[i]->GetData().level;
	}

	int avgPoint = static_cast<int>(accPoint / fairyCount);
	int avgLevel = static_cast<int>(accLevel / fairyCount);

/*    최소 레벨 공식
              기존: 레벨 평균 * 2 / 3
              변경: 환생점수 평균
    최대 레벨 공식
              기존: 레벨 평균 * 4 / 3
              변경: 환생점수 평균 * 2
*/
	clsData.level = NUtil::GetRandBetween(avgPoint, avgPoint * 2) + (avgLevel / 10);

	// 페어리 환생 레벨 MAX 체크
	int limitLevel = Static::InstancePtr()->GetCommon()->GetLimitLevel(pUser);
	if (-1 == limitLevel)
	{
		DEBUGLOG("%s : limitLevel get fail.", __FUNCTION__);
		return false;
	}

	if (limitLevel < clsData.level)
	{
		clsData.level = limitLevel;
	}

	// 페어리 환생 등급 결정
	accPoint = 0;
	for (int i = 0; i < fairyCount; i++)
	{
		int point = (fairys[i]->GetData().quality * pBalance->GetValue(EM_FAIRY_REBIRTH_GRADE_POINT_GAP)) + pBalance->GetValue(EM_FAIRY_REBIRTH_GRADE_POINT_START);
		accPoint += point;
	}

	// 최종 등급 점수 = randbetween(0,70) + 누적 등급 점수
	int qualityPoint = NUtil::GetRandBetween(0, 70) + accPoint;

	clsData.quality = Static::InstancePtr()->GetRebirthQualityResource()->GetRebirthQuality(qualityPoint);

	// 페어리 환생 등급이 MAX OPEN 등급 이상인 경우 MAX OPEN 등급 으로 설정
	if (clsData.quality > MAX_OPEN_FAIRY_QUALITY)
	{
		clsData.quality = MAX_OPEN_FAIRY_QUALITY;
	}




#if 0
	clsData.quality = ITEM_QUALITY_SSS;

	for (; clsData.quality >= 0; clsData.quality--)
	{
		if (qualityPoint >= (clsData.quality * pBalance->GetValue(EM_FAIRY_REBIRTH_GRADE_GAP)))
		{
			break;
		}
	}

	// 페어리 환생 등급이 6성 이상인 경우 6성으로 설정
	if (clsData.quality >= 5)
	{
		clsData.quality = 5;	// 6성
	}

	// 재료 페어리 중에 7성 이상이 있으면 재료 페어리의 등급으로 환생
	if (maxQuality >= 6)
	{
		clsData.quality = maxQuality;
	}
#endif




	DEBUGLOG("ACCPOINT=%d, QUALITY_POINT=%d, MAX=%d, QUALITY=%d", accPoint, qualityPoint, maxQuality, clsData.quality);

	bool bEvent = IsFairyGachyaEvent(pUser);

	// 페어리 속성 타입 결정
	clsData.eff_type[0]	= GetFairyAttrType(pFairy, bEvent, -1);

	// 페어리 전투 타입 결정
	clsData.eff_pos[0]	= GetFairyBattleType(pFairy, bEvent);

	// 페어리 보유 패시브 갯수 결정
	int passive		= GetFairyPassiveCount(pFairy, bEvent, clsData.quality);

	// 페어리 버프 결정
	int buff		= GetFairyBuff(pFairy, pBalance, bEvent, clsData.quality);

	// 페어리 타입 결정
	int fairytype	= GetFairyType(pFairy, bEvent);

	// 페어리 정보 설정
	if (false == SetFairyInfo(pFairy, pBalance, clsData, passive, buff, fairytype, bEvent))
	{
		return false;
	}

	return true;
}


int
FairyGachyaResource::FairyUltimateEvolution(User * pUser, NLogic::Item * pItem)
{
	UltimateEvolutionRateResource::Flyweight * pFly = Static::InstancePtr()->GetUltimateRateResource()->GetFly(pItem->GetData().quality);
	if (NULL == pFly)
	{
		DEBUGLOG("%s : pFly is NULL", __FUNCTION__);
		return ACK_UNKNOWN_ERROR;
	}

	int randRate = rand() % 100;

	// 진화 실패
	if (pFly->_FAIRY < randRate)
	{
		return ACK_FAIRY_EVOLUTION_FAIL;
	}

	// 진화
	pItem->GetData().quality += 1;

	return ACK_OK;
}

int
FairyGachyaResource::FairyEvolution(User * pUser, NLogic::Item * pItem)
{
	FairyEvolutionRateResource::Flyweight * pFly = Static::Instance().GetFairyEvolutionRateResource()->GetFly(pItem->GetData().quality);
	if (NULL == pFly)
	{
		DEBUGLOG("%s : pFly is NULL", __FUNCTION__);
		return ACK_UNKNOWN_ERROR;
	}

	int randRate = rand() % 100;

	// 진화 실패
	if (pFly->_DEFAULT_RATE < randRate)
	{
		return ACK_FAIRY_EVOLUTION_FAIL;
	}

	// 진화 성공. 속성값 재정의
	{
		pItem->GetData().quality += 1;
		pItem->GetData().level	= 1;

		FairyGachyaData * pFairy = this->GetDataPtr(pUser->GetCompany(), pUser->GetSaleCode());
		if (pFairy == NULL)
		{
			DEBUGLOG("%s : pFairy is NULL", __FUNCTION__);
			return ACK_UNKNOWN_ERROR;
		}

		int type = static_cast<int>(EM_FAIRY_GACHYA_BATTLETYPE_CONST);

		FairyGachyaData::Key clsKey(type, pItem->GetData().eff_pos[0]);
		FairyGachyaData::Flyweight * pFly1 = pFairy->GetFly(clsKey);

		if (NULL == pFly1)
		{
			DEBUGLOG("%s : pFly1 is NULL! type=%d, battletype=%d", __FUNCTION__, type, pItem->GetData().eff_pos[0]);
			return ACK_UNKNOWN_ERROR;
		}

		FairyGachyaData::Key clsKey2(type, 5);
		FairyGachyaData::Flyweight * pFly2 = pFairy->GetFly(clsKey2);

		if (NULL == pFly2)
		{
			DEBUGLOG("%s : pFly2 is NULL! type=%d, subtype=5", __FUNCTION__, type);
			return ACK_UNKNOWN_ERROR;
		}

		// 페어리 전투 타입 별 공격 속성값 / 방어 속성값 결정
		int attValue	= pFly1->_VALUE1;	// 공격 하한값
		int attGap		= pFly2->_VALUE1;	// 공격 하한값 간격
		int defValue	= pFly1->_VALUE2;	// 방어 하한값
		int defGap		= pFly2->_VALUE2;	// 방어 하한값 간격

		int mainAtt	= NUtil::GetRandBetween(attValue, attValue + attGap) * 0.2;		// 공격 주속성

		int subDef	= NUtil::GetRandBetween(defValue, defValue + defGap) * 0.2;		// 방어 부속성1
		if (0 >= subDef) {
			subDef = 1;
		}

		int subDef2	= NUtil::GetRandBetween(defValue, defValue + defGap) * 0.2;		// 방어 부속성2
		if (0 >= subDef2) {
			subDef2 = 1;
		}

		int subDef3	= NUtil::GetRandBetween(defValue, defValue + defGap) * 0.2;		// 방어 부속성3
		if (0 >= subDef3) {
			subDef3 = 1;
		}

		int mainDef	= 20 - mainAtt - (subDef + subDef2 + subDef3);		// 방어 주속성

		pItem->GetData().eff_value[1]	= mainAtt * pItem->GetData().level;

		switch (pItem->GetData().eff_type[0])
		{
		case 0:	/// 화염
			pItem->GetData().eff_value[2] = mainDef * pItem->GetData().level;
			pItem->GetData().eff_value[3] = subDef * pItem->GetData().level;
			pItem->GetData().eff_value[4] = subDef2 * pItem->GetData().level;
			pItem->GetData().eff_value[5] = subDef3 * pItem->GetData().level;
			break;

		case 1:	// 냉기
			pItem->GetData().eff_value[2] = subDef * pItem->GetData().level;
			pItem->GetData().eff_value[3] = mainDef * pItem->GetData().level;
			pItem->GetData().eff_value[4] = subDef2 * pItem->GetData().level;
			pItem->GetData().eff_value[5] = subDef3 * pItem->GetData().level;
			break;

		case 2:	// 신성
			pItem->GetData().eff_value[2] = subDef * pItem->GetData().level;
			pItem->GetData().eff_value[3] = subDef2 * pItem->GetData().level;
			pItem->GetData().eff_value[4] = mainDef * pItem->GetData().level;
			pItem->GetData().eff_value[5] = subDef3 * pItem->GetData().level;
			break;

		case 3:	// 암흑
			pItem->GetData().eff_value[2] = subDef * pItem->GetData().level;
			pItem->GetData().eff_value[3] = subDef2 * pItem->GetData().level;
			pItem->GetData().eff_value[4] = subDef3 * pItem->GetData().level;
			pItem->GetData().eff_value[5] = mainDef * pItem->GetData().level;
			break;
		}
	}

	return ACK_OK;
}


bool
FairyGachyaResource::SetFairyInfo(FairyGachyaData * pFairy, NResource::BalanceData * pBalance, NLogic::Item::Data & clsData, int passive, int buff, int fairyType, bool bEvent)
{
	int type = static_cast<int>(EM_FAIRY_GACHYA_BATTLETYPE_CONST);

	if (true == bEvent) {
		type = static_cast<int>(EM_FAIRY_GACHYA_BATTLETYPE_CONST_EVENT);
	}

	FairyGachyaData::Key clsKey(type, clsData.eff_pos[0]);
	FairyGachyaData::Flyweight * pFly = pFairy->GetFly(clsKey);

	if (NULL == pFly)
	{
		DEBUGLOG("SetFairyInfo : pFly is NULL! type=%d, battletype=%d", type, clsData.eff_pos[0]);
		return false;
	}

	FairyGachyaData::Key clsKey2(type, 5);
	FairyGachyaData::Flyweight * pFly2 = pFairy->GetFly(clsKey2);

	if (NULL == pFly2)
	{
		DEBUGLOG("SetFairyInfo : pFly2 is NULL! type=%d, subtype=5", type);
		return false;
	}


	// 페어리 전투 타입 별 공격 속성값 / 방어 속성값 결정
	int attValue	= pFly->_VALUE1;	// 공격 하한값
	int attGap		= pFly2->_VALUE1;	// 공격 하한값 간격
	int defValue	= pFly->_VALUE2;	// 방어 하한값
	int defGap		= pFly2->_VALUE2;	// 방어 하한값 간격

	int mainAtt	= NUtil::GetRandBetween(attValue, attValue + attGap) * 0.2;		// 공격 주속성

	int subDef	= NUtil::GetRandBetween(defValue, defValue + defGap) * 0.2;		// 방어 부속성1
	if (0 >= subDef) {
		subDef = 1;
	}

	int subDef2	= NUtil::GetRandBetween(defValue, defValue + defGap) * 0.2;		// 방어 부속성2
	if (0 >= subDef2) {
		subDef2 = 1;
	}

	int subDef3	= NUtil::GetRandBetween(defValue, defValue + defGap) * 0.2;		// 방어 부속성3
	if (0 >= subDef3) {
		subDef3 = 1;
	}

	int mainDef	= 20 - mainAtt - (subDef + subDef2 + subDef3);		// 방어 주속성

	clsData.tid			= (fairyType * 4) + clsData.eff_type[0];
	clsData.sub_type	= EnumClassItemTableType::CLASS_ITEM_TABLE_FAIRY;
	clsData.class_type	= -1;
	clsData.bag_type	= INVEN_BAG_TYPE::BAG_TYPE_FAIRY;
	clsData.quantity	= 1;

	clsData.evolve_point = -1;
	clsData.evolve_percent = -1;

	int tidMin = pBalance->GetValue(EM_FAIRY_PASSIVE_TID_MIN);
	int tidMax = pBalance->GetValue(EM_FAIRY_PASSIVE_TID_MAX);

	// 페어리 스킬 레벨 = int((페어리 레벨 / 100)* 10)
	// (최소: 1, 최대: 10)
	int skillLevel = (clsData.level * 10) / 100.0;

	if (skillLevel <= 0)
		skillLevel = 1;
	else if (skillLevel > 10)
		skillLevel = 10;

	for (int i = 0; i < passive; i++)
	{
		switch (i)
		{
		case 0:
			clsData.eff_value[0]	= NUtil::GetRandBetween(tidMin, tidMax);
			clsData.eff_pos[1]		= skillLevel;
			break;
		case 1:
			clsData.eff_value[6]	= NUtil::GetRandBetween(tidMin, tidMax);
			clsData.eff_pos[2]		= skillLevel;
			break;
		case 2:
			clsData.evolve_point	= NUtil::GetRandBetween(tidMin, tidMax);
			clsData.eff_pos[3]		= skillLevel;
			break;
		}
	}

	clsData.eff_value[1]	= mainAtt * clsData.level;

	switch (clsData.eff_type[0])
	{
	case 0:	/// 화염
		clsData.eff_value[2] = mainDef * clsData.level;
		clsData.eff_value[3] = subDef * clsData.level;
		clsData.eff_value[4] = subDef2 * clsData.level;
		clsData.eff_value[5] = subDef3 * clsData.level;
		break;

	case 1:	// 냉기
		clsData.eff_value[2] = subDef * clsData.level;
		clsData.eff_value[3] = mainDef * clsData.level;
		clsData.eff_value[4] = subDef2 * clsData.level;
		clsData.eff_value[5] = subDef3 * clsData.level;
		break;

	case 2:	// 신성
		clsData.eff_value[2] = subDef * clsData.level;
		clsData.eff_value[3] = subDef2 * clsData.level;
		clsData.eff_value[4] = mainDef * clsData.level;
		clsData.eff_value[5] = subDef3 * clsData.level;
		break;

	case 3:	// 암흑
		clsData.eff_value[2] = subDef * clsData.level;
		clsData.eff_value[3] = subDef2 * clsData.level;
		clsData.eff_value[4] = subDef3 * clsData.level;
		clsData.eff_value[5] = mainDef * clsData.level;
		break;
	}

	clsData.evolve_percent	= buff;
	if (buff > 0)
	{
		// 페어리 버프 스킬 레벨
		clsData.eff_pos[4]	= skillLevel;
	}

	return true;
}

} /* NResource */ } /* ProjectZ */



